/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/* 
 * File:   pipe_meta.
 * Author: picci
 *
 * Created on June 3, 2011, 12:37 PM
 */

#ifndef PIPE_META_
#define	PIPE_META_

#include <string>
#include <map>
#include <utility>

#include "prj_definitions.h"
#include "common/utility_data_structures.h"
#include "configuration/configuration.h"
#include "pipeline_data_structures.h"

namespace NAMESPACE{

// ###### DESCRIPTORS ##########################################################
    
class PDSVisitor;

// ****** PipeStepDescriptor definition ****************************************    
class PipeStepDescriptor{
protected:
    std::string id;
    std::map< IOKey, std::pair<std::string, Configuration> > in_generators;
    std::map< IOKey, std::pair<std::string, Configuration> > out_generators;
    std::map< IOKey, std::map<std::string, Configuration> > formatters;
    std::map< IOKey, std::string > criteria;
    
public:
    ~PipeStepDescriptor();
    PipeStepDescriptor();
    PipeStepDescriptor(const PipeStepDescriptor& d);
    PipeStepDescriptor(const std::string& id);
    const PipeStepDescriptor& operator=(const PipeStepDescriptor& d);
    
    // *** Getters
    
    const std::string&                           get_id() const;
    virtual void                                 get_computation(PDSVisitor& v) const = 0;
    virtual const std::string&                   get_computation_name() const = 0;
    const std::pair<std::string, Configuration>& get_in_gen(const IOKey& k) const;
    const Configuration&                         get_in_conf(const IOKey& k, const std::string& gen) const;
    const std::pair<std::string, Configuration>& get_out_gen(const IOKey& k) const;
    const Configuration&                         get_out_conf(const IOKey& k, const std::string& gen) const;
    const std::map<std::string, Configuration>&  get_formatters(const IOKey& k) const;
    const Configuration&                         get_formatter_conf(const IOKey& k, const std::string& form) const;
    const std::string&                           get_criteria(const IOKey& k) const;
    
    // *** Setters
    
    virtual PipeStepDescriptor& set_computation(const PDSVisitor& v) = 0;
    PipeStepDescriptor& set_id(const std::string& id);
    PipeStepDescriptor& set_in_gen(const IOKey& k, const std::pair<std::string, Configuration>& gen);
    PipeStepDescriptor& set_in_conf(const IOKey& k, const std::string& gen, const Configuration& conf);
    PipeStepDescriptor& set_out_gen(const IOKey& k, const std::pair<std::string, Configuration>& gen);
    PipeStepDescriptor& set_out_conf(const IOKey& k, const std::string& gen, const Configuration& conf);
    PipeStepDescriptor& set_formatters(const IOKey& k, const std::map<std::string, Configuration>& formatter);
    PipeStepDescriptor& set_formatter_conf(const IOKey& k, const std::string& form, const Configuration& conf);
    PipeStepDescriptor& set_criteria(const IOKey& k, const std::string& value);
    
    
    const std::map<IOKey, std::string>& get_all_criteria() const;
    const std::map< IOKey, std::pair<std::string, Configuration> >& get_all_in_generators() const;
    const std::map< IOKey, std::pair<std::string, Configuration> >& get_all_out_generators() const;
    const std::map< IOKey, std::map<std::string, Configuration> >&  get_all_formatters() const;
    
    virtual PipeStepDescriptor* clone() const = 0;
};
// -----------------------------------------------------------------------------
// _____________________________________________________________________________


// _____________________________________________________________________________


// ###### DESCRIPTOR CONSUMERS #################################################

// ****** PipeStepDescrConsumer definition *************************************
class PipeStepDescrConsumer{
public:
    virtual ~PipeStepDescrConsumer(){}
    virtual void consume(const PipeStepDescriptor& d) = 0;
};
// -----------------------------------------------------------------------------

// ****** AbsPipeStepDescrConsumer definition **********************************
class AbsPipeStepDescrConsumer : public PipeStepDescrConsumer{
public:    
    virtual ~AbsPipeStepDescrConsumer();
    AbsPipeStepDescrConsumer();
    AbsPipeStepDescrConsumer(const AbsPipeStepDescrConsumer& c);
    const AbsPipeStepDescrConsumer& operator=(const AbsPipeStepDescrConsumer& c);
    virtual void consume(const PipeStepDescriptor& d) = 0;
};
// -----------------------------------------------------------------------------

// _____________________________________________________________________________


// ###### DESCRIPTOR BUILDERS ##################################################

class PipelineDescriptor;
class SingleStepDescriptor;

// ****** PipeStepDescrBuilder definition **************************************
class PipeStepDescrBuilder{
public:
    virtual ~PipeStepDescrBuilder(){}
    virtual void build(std::vector<PipeStepDescriptor*>&) = 0;
};
// -----------------------------------------------------------------------------

// ****** AbsPipeStepDescrBuilder definition **********************************
class AbsPipeStepDescrBuilder : public PipeStepDescrBuilder{
public:    
    virtual ~AbsPipeStepDescrBuilder(){}
    virtual void build(std::vector<PipeStepDescriptor*>&) = 0;
};
// -----------------------------------------------------------------------------

// _____________________________________________________________________________




// ###### VISITORS #############################################################

// ****** PDSVisitor definition ************************************************
class PDSVisitor{
public:
    virtual ~PDSVisitor(){}
    
    virtual void get_pipeline(const PipelineDescriptor& d) = 0;
    virtual void get_single_step(const SingleStepDescriptor& d) = 0;
    
    virtual void set_pipeline(PipelineDescriptor& d) const = 0;
    virtual void set_single_step(SingleStepDescriptor& d) const = 0;
};    
// -----------------------------------------------------------------------------

// ****** AbsPDSVisitor definition *********************************************
class AbsPDSVisitor :  public PDSVisitor{
public:
    virtual ~AbsPDSVisitor(){}
    
    virtual void get_pipeline(const PipelineDescriptor& d) = 0;
    virtual void get_single_step(const SingleStepDescriptor& d) = 0;
    
    virtual void set_pipeline(PipelineDescriptor& d) const = 0;
    virtual void set_single_step(SingleStepDescriptor& d) const = 0;
};    
// -----------------------------------------------------------------------------

// ****** GenericPDSVisitor definition *****************************************
class GenericPDSVisitor : public AbsPDSVisitor{
private:
    PipeStepComputation* computation; // output
    
    PipeStepDescrBuilder* descr_builder; // input
    std::string computation_name;        // input
    
public:
    void get_pipeline(const PipelineDescriptor& d);
    void get_single_step(const SingleStepDescriptor& d);
    
    void set_pipeline(PipelineDescriptor& d) const;
    void set_single_step(SingleStepDescriptor& d) const;
    
    void set_computation_name(const std::string& name);
    void set_descr_builder(PipeStepDescrBuilder* builder);
    
    PipeStepComputation* get_computation() const;
    
};    
// -----------------------------------------------------------------------------

// _____________________________________________________________________________



// ###### DESCRIPTORS ##########################################################

// ****** PipelineDescriptor definition ****************************************
class PipelineDescriptor : public PipeStepDescriptor{
private:
    std::vector<PipeStepDescriptor*> computation;
    std::string computation_name;
    
public:
    PipelineDescriptor();
    PipelineDescriptor(const std::string& id) : PipeStepDescriptor(id), computation(), computation_name(){}
    PipelineDescriptor(const PipelineDescriptor& p);
    ~PipelineDescriptor();
    
    PipeStepDescriptor& add_step(const PipeStepDescriptor& step);
    
    void get_computation(PDSVisitor& v) const { v.get_pipeline(*this); }
    const std::string& get_computation_name() const { return computation_name;}
    std::vector<PipeStepDescriptor*>& get_computation_steps() { return computation; }
    const std::vector<PipeStepDescriptor*>& get_computation_steps() const { return computation; }
    PipeStepDescriptor& set_computation(const PDSVisitor& v) { v.set_pipeline(*this); return *this; }
    PipeStepDescriptor& set_computation(const std::vector<PipeStepDescriptor*>& _computation) { computation = _computation; }
    
    PipeStepDescriptor* clone() const{
        return new PipelineDescriptor(*this);
    }
};
// -----------------------------------------------------------------------------

// ****** SingleStepDescriptor definition **************************************
class SingleStepDescriptor : public PipeStepDescriptor{
private:
    std::string computation;
    
public:
    SingleStepDescriptor() : PipeStepDescriptor(), computation(){}
    SingleStepDescriptor(const std::string& id) : PipeStepDescriptor(id), computation(){}
    SingleStepDescriptor(const SingleStepDescriptor& s) : PipeStepDescriptor(s), 
                                                          computation(s.computation){}
    
    void get_computation(PDSVisitor& v) const { v.get_single_step(*this); }
    const std::string& get_computation_name() const { return computation;}
    PipeStepDescriptor& set_computation(const PDSVisitor& v) { v.set_single_step(*this); return *this; }
    PipeStepDescriptor& set_computation(const std::string& str) { computation = str; return *this; }
    
    PipeStepDescriptor* clone() const{
        return new SingleStepDescriptor(*this);
    }
};
// -----------------------------------------------------------------------------

// _____________________________________________________________________________
}

#endif	/* PIPE_META_ */
